#if !defined(___JPEG2_C)
#define ___JPEG2_C
#include "std.h"


static Str units[]=
{ "pix", "dpi", "dpc"
};
static Str htyp[]=
{ "dc", "ac"
};


static tQtab *getqt(tQtab *qtab,N1 qid)
{ N1 n1; for (n1=0;n1<QMAX;++n1,++qtab)
  { if (qtab->qid==0xFF)
      continue;
    if (qtab->qid==qid)
      return (qtab);
  }
  return (NULL);
}
static tHtab *getht(tHtab *htab,N1 hid,N1 typ)
{ N1 n1; for (n1=0;n1<HMAX;++n1,++htab)
  { if (htab->hid==0xFF)
      continue;
    if (htab->hid==hid &&
        htab->typ==typ)
      return (htab);
  }
  return (NULL);
}


static Str help2=
  "Args: -h| [-v(0-4)] [-i<file_jpg>] [-o<file_out>] [-b<file_bmp>]\n"
  "Defs: -v:4, -i:<stdin>, -o:<stdout>, -b:<none>";
I4 opts2(tProg *prg,int argc,char **argv)
{ FILE *f1; N4 i;
  if (!prg) ERR1("Error: opts: NULL prg",0ul);
  prg->msg=4;
  prg->fi=stdin;
  prg->fo=stdout;
  prg->fb=NULL;

  if (!argc && !argv)
  { puts(help2); return (0); }
  for (++argv,i=1;i<argc;++i)
  { Str s1=*(argv++);
    if (s1[0]!='-') continue;
    switch (s1[1])
    { case 'h':
        puts(help2);
        exit(0);
      case 'v':
        prg->msg=s1[2]-'0';
        break;
      case 'i':
        if (!(f1=fopen(s1+2,"rb")))
          ERR1("Error: Open Input",0l);
        prg->fi=f1;
        break;
      case 'o':
        if (!(f1=fopen(s1+2,"wb")))
          ERR1("Error: Open Output",0l);
        prg->fo=f1;
        break;
      case 'b':
        if (!(f1=fopen(s1+2,"wb")))
          ERR1("Error: Open Bitmap",0l);
        prg->fb=f1;
        break;
    }
  }
  return (0);
}
xx jpeg2Beg(tJpeg2 *jpg)
{ N4 i1;
  jpg->bmp=NULL;
  for (i1=0;i1<CNUM;++i1)
  { jpg->pp[i1]=NULL;
  }
  for (i1=0;i1<HMAX;++i1)
  { jpg->htab[i1].val=NULL;
    jpg->htab[i1].hufsiz=NULL;
    jpg->htab[i1].hufcod=NULL;
  }
}
xx jpeg2End(tJpeg2 *jpg)
{ N4 i1;
  if (jpg->bmp)
    MemRel(jpg->bmp->pp);
  for (i1=0;i1<CNUM;++i1)
  { MemRel(jpg->pp[i1]);
  }
  for (i1=0;i1<HMAX;++i1)
  { MemRel(jpg->htab[i1].val);
    MemRel(jpg->htab[i1].hufsiz);
    MemRel(jpg->htab[i1].hufcod);
  }
}
int jpeg2a(int argc,char **argv)
{ I4 i1; tJpeg2 jpg;
  jpeg2Beg(&jpg);
  if (!(i1=opts2(prg,argc,argv)))
    i1=jpeg2b(&jpg,prg->fi,prg->fb);
  jpeg2End(&jpg);
  if (prg->fi!=stdin) fclose(prg->fi);
  if (prg->fo!=stdout) fclose(prg->fo);
  if (prg->fb) fclose(prg->fb);
  if (i1==-1l) return (-1);
  return (0);
}
I4 jpeg2b(tJpeg2 *jpg,FILE *fi,FILE *fb)
{ N1 cc,c1; int ii; N4 nn=0,ll=0;
  tApp app; tSof sof; tSos sos;
  tComp comp[CNUM];
  tComp2 comp2[CNUM];
  tQtab qtab[QMAX]; N1 qn=0;
  tHtab htab[HMAX]; N1 hn=0;
  N4 n1,n2; tGetBit bb;
  N1 image=0;
  bb.nn=&nn; bb.f1=fi;
  bb.cnt=0; bb.bb=0;
  DctInit();

#if defined(___OS_WIN)
  setmode(fileno(stdin),O_BINARY);
  setmode(fileno(stdout),O_BINARY);
  setmode(fileno(stderr),O_BINARY);
#endif

  app.ver[0]=0; app.ver[1]=0;
  sof.comps=0; sos.comps=0;
  for (c1=0;c1<QMAX;++c1)
    qtab[c1].qid=0xFF;
  for (c1=0;c1<HMAX;++c1)
    htab[c1].hid=0xFF;
  while (1)
  { GETC; if (ii==-1) break;
    if (ll) { --ll; continue; }
    if (cc!=0xFF)
    { if (image)
      { WARN1("Warn: Image: More",nn-1);
        break;
      }
      if (!app.ver[0] && !app.ver[1])
        WARN1("Warn: Image: Check",nn-1);
      if (!sof.comps || !sos.comps)
        ERR1("Error: Image: Check",nn-1);
      image=1; bb.cnt=8; bb.bb=cc;
      if (conv2(&nn,jpg,&sof,comp,comp2,
        htab,qtab,&bb,fb)==-1l)
        return (-1l);
      continue;
    }
    if (cc!=0xFF) //continue;
      ERR1("Error: Missing 0xFF",nn-1);
    while (1)
    { GETC; if (ii==-1)
        ERR1("Error: Missing Marker",nn-1);
      if (cc!=0xFF) break;
    }
    switch (cc)
    { case 0x00: // Escaped 0xFF
        ERR1("Error: Unexpected 0xFF",nn-2);
        break;
      case 0xD8: // SOI
        MSG1("Marker: SOI",nn-2);
        break;
      case 0xD9: // EOI
        MSG1("Marker: EOI",nn-2);
        break;
      case 0x01: // TEM
        MSG1("Marker: TEM",nn-2);
        break;
      case 0xD0:
      case 0xD1:
      case 0xD2:
      case 0xD3:
      case 0xD4:
      case 0xD5:
      case 0xD6:
      case 0xD7: // RSTi
        WARN2("Warn: Marker: RST%u",nn-2,(N2)cc-0xD0);
        break;
      default: c1=cc;
        MSG2("Marker: 0x%02X",nn-2,(N2)cc);
        GETC; if (ii==-1)
          ERR1("Error: Missing Length/1",nn);
        ll=(N4)cc;
        GETC; if (ii==-1)
          ERR1("Error: Missing Length/2",nn-1);
        ll=(ll<<8)|(N4)cc; if (ll<2)
          ERR1("Error: Invalid length",nn-2);
        MSG3("Len: 0x%04lX (%lu)",nn-2,ll,ll);
        ll-=2; switch (c1)
        { case 0xE0:
            MSG1("Marker: APP0",nn-4);
            if (ll<14)
              ERR1("Error: Invalid length",nn-2);
            // Identifier (5)
            { N1 buf[5],*s1="JFIF";
              for (c1=0;c1<5;++c1)
              { GETC; if (ii==-1)
                  ERR1("Error: Missing ID",nn);
                buf[c1]=cc;
              }
              if (StrCmp(buf,s1))
                ERR1("Error: Invalid ID",nn-5);
              MSG2("  APP0: %s",nn-5,s1);
            } ll-=5;
            // Version (2)
            GETC; if (ii==-1)
              ERR1("Error: Missing Version/1",nn);
            app.ver[0]=cc;
            GETC; if (ii==-1)
              ERR1("Error: Missing Version/2",nn-1);
            app.ver[1]=cc;
            MSG3("  Ver: %u.%u",nn-2,
              (N2)app.ver[0],(N2)app.ver[1]);
            if (app.ver[0]!=1)
              ERR1("Error: Invalid Version/1",nn-2);
            if (app.ver[1]<1)
              WARN1("Warn: Invalid Version/2",nn-1);
            ll-=2;
            // Units (1)
            GETC; if (ii==-1)
              ERR1("Error: Missing Units",nn);
            app.units=cc;
            if (app.units>2)
              ERR2("Error: Invalid Units: %u",nn-1,(N2)app.units);
            MSG3("  Units: %s (%u)",nn-1,
              units[app.units],(N2)app.units);
            ll-=1;
            // X Density (2)
            GETC; if (ii==-1)
              ERR1("Error: Missing X Density/1",nn);
            app.xden=(N2)cc;
            GETC; if (ii==-1)
              ERR1("Error: Missing X Density/2",nn-1);
            app.xden=(app.xden<<8)|(N2)cc;
            MSG2("  XDen: %u",nn-2,app.xden);
            ll-=2;
            // Y Density (2)
            GETC; if (ii==-1)
              ERR1("Error: Missing Y Density/1",nn);
            app.yden=(N2)cc;
            GETC; if (ii==-1)
              ERR1("Error: Missing Y Density/2",nn-1);
            app.yden=(app.yden<<8)|(N2)cc;
            MSG2("  YDen: %u",nn-2,app.yden);
            ll-=2;
            // X Thumbnail (1)
            GETC; if (ii==-1)
              ERR1("Error: Missing X Thumbnail",nn);
            app.xthumb=cc;
            MSG2("  XThumb: %u",nn-1,(N2)app.xthumb);
            ll-=1;
            // Y Thumbnail (1)
            GETC; if (ii==-1)
              ERR1("Error: Missing Y Thumbnail",nn);
            app.ythumb=cc;
            MSG2("  YThumb: %u",nn-1,(N2)app.ythumb);
            ll-=1;
            // Thumbnail
            if (ll!=3ul*(N4)app.xthumb*(N4)app.ythumb)
              ERR2("Error: Invalid Thumbnail[%lu]",nn,ll);
            MSG2("  Thumb[%lu]",nn,ll);
            break;
          case 0xE1:
            MSG1("Marker: APP1",nn-4);
            if (ll<5)
              ERR1("Error: Invalid length",nn-2);
            // Identifier (5)
            { N1 buf[5],*s1="Exif";
              for (c1=0;c1<5;++c1)
              { GETC; if (ii==-1)
                  ERR1("Error: Missing ID",nn);
                buf[c1]=cc;
              }
              if (StrCmp(buf,s1))
                WARN1("Warn: Invalid ID",nn-5);
              else MSG2("  APP1: %s",nn-5,s1);
            } ll-=5;
            break;
          case 0xE2:
          case 0xE3:
          case 0xE4:
          case 0xE5:
          case 0xE6:
          case 0xE7:
          case 0xE8:
          case 0xE9:
          case 0xEA:
          case 0xEB:
          case 0xEC:
          case 0xED:
          case 0xEE:
          case 0xEF:
            WARN2("Warn: Marker: APP%u",nn-4,(N2)c1-0xE0);
            break;
          case 0xC0:
          case 0xC1:
          case 0xC2:
          case 0xC3:
          case 0xC5:
          case 0xC6:
          case 0xC7:
          case 0xC9:
          case 0xCA:
          case 0xCB:
          case 0xCD:
          case 0xCE:
          case 0xCF:
            MSG2("Marker: SOF%u",nn-4,(N2)c1-0xC0);
            if (c1!=0xC0 && c1!=0xC1)
              ERR2("Error: Unknown SOF%u",nn-4,(N2)c1-0xC0);
            if (ll<6)
              ERR1("Error: Invalid length",nn-2);
            // Precision (1)
            GETC; if (ii==-1)
              ERR1("Error: Missing Precision",nn);
            sof.prec=cc;
            MSG2("  Prec: %u",nn-1,(N2)sof.prec);
            if (sof.prec!=8)
              ERR1("Error: Invalid Precision",nn-1);
            ll-=1;
            // Y Length (2)
            GETC; if (ii==-1)
              ERR1("Error: Missing Y Length/1",nn);
            sof.yl=(N2)cc;
            GETC; if (ii==-1)
              ERR1("Error: Missing Y Length/2",nn-1);
            sof.yl=(sof.yl<<8)|(N2)cc;
            MSG2("  YLen : %u",nn-2,sof.yl);
            ll-=2;
            // X Length (2)
            GETC; if (ii==-1)
              ERR1("Error: Missing X Length/1",nn);
            sof.xl=(N2)cc;
            GETC; if (ii==-1)
              ERR1("Error: Missing X Length/2",nn-1);
            sof.xl=(sof.xl<<8)|(N2)cc;
            MSG2("  XLen : %u",nn-2,sof.xl);
            ll-=2;
            // Comp Num (1)
            GETC; if (ii==-1)
              ERR1("Error: Missing Comp Num",nn);
            sof.comps=cc;
            MSG2("  CompNum: %u",nn-1,(N2)sof.comps);
            if (sof.comps!=CNUM)
              ERR1("Error: Invalid Comp Num",nn-1);
            ll-=1;
            // Components [C/8,X/4,Y/4,Q/8]
            if (ll!=3*(N2)sof.comps)
              ERR2("Error: Invalid length: %lu",nn,ll);
            for (c1=0;c1<sof.comps;++c1)
            { // CID/8
              GETC; if (ii==-1)
                ERR1("Error: Missing CID",nn);
              comp[c1].cid=cc;
              MSG2("  CID: %u",nn-1,(N2)comp[c1].cid);
              // Xd/4,Yd/4
              GETC; if (ii==-1)
                ERR1("Error: Missing Dens",nn);
              comp[c1].xd=cc>>4;
              comp[c1].yd=cc&0xF;
              MSG3("  Xd,Yd: %u,%u",nn-1,
                (N2)comp[c1].xd,(N2)comp[c1].yd);
              cc=comp[c1].xd; if (cc!=1 && cc!=2 && cc!=4)
                ERR1("Error: Invalid XDens",nn-1);
              cc=comp[c1].yd; if (cc!=1 && cc!=2 && cc!=4)
                ERR1("Error: Invalid YDens",nn-1);
              // QID/8
              GETC; if (ii==-1)
                ERR1("Error: Missing QID",nn);
              comp[c1].qid=cc;
              MSG2("  QID: %u",nn-1,(N2)comp[c1].qid);
              cc=comp[c1].qid; if (cc>=QMAX)
                ERR1("Error: Invalid QID",nn-1);
            } ll=0;
            break;
          case 0xDA:
            MSG1("Marker: SOS",nn-4);
            // Comp Num (1)
            if (ll<1)
              ERR1("Error: Missing Comp Num: Len",nn);
            GETC; if (ii==-1)
              ERR1("Error: Missing Comp Num: Eof",nn);
            sos.comps=cc;
            MSG2("  CompNum: %u",nn-1,(N2)sos.comps);
            if (sos.comps!=sof.comps)
              ERR1("Error: Invalid Comp Num",nn-1);
            ll-=1;
            // Components [C/1,Hdc/4,Hac/4]
            if (ll<2*(N2)sos.comps)
              ERR2("Error: Invalid length: %lu",nn,ll);
            for (c1=0;c1<sos.comps;++c1)
            { // CID/8
              GETC; if (ii==-1)
                ERR1("Error: Missing CID",nn);
              comp2[c1].cid=cc;
              MSG2("  CID: %u",nn-1,(N2)comp2[c1].cid);
              if (comp2[c1].cid!=comp[c1].cid)
                ERR1("Error: Wrong CID",nn-1);
              // HDC/4,HAC/4
              GETC; if (ii==-1)
                ERR1("Error: Missing HID",nn);
              comp2[c1].hdc=cc>>4;
              comp2[c1].hac=cc&0xF;
              MSG3("  hdc,hac: %u,%u",nn-1,
                (N2)comp2[c1].hdc,(N2)comp2[c1].hac);
              if (comp2[c1].hdc>=HNUM)
                ERR1("Error: Invalid HDC",nn-1);
              if (comp2[c1].hac>=HNUM)
                ERR1("Error: Invalid HAC",nn-1);
            } ll-=2*(N2)sos.comps;
            if (ll!=3)
              ERR1("Error: Invalid Length",nn);
            // Start Qt (1)
            GETC; if (ii==-1)
              ERR1("Error: Missing Start Qt",nn);
            sos.q1=cc;
            MSG2("  Start Qt: %u",nn-1,(N2)sos.q1);
            if (sos.q1!=0)
              ERR1("Error: Invalid Start Qt",nn-1);
            // Stop Qt (1)
            GETC; if (ii==-1)
              ERR1("Error: Missing Stop Qt",nn);
            sos.q2=cc;
            MSG2("  Stop Qt: %u",nn-1,(N2)sos.q2);
            if (sos.q2!=63)
              ERR1("Error: Invalid Stop Qt",nn-1);
            // Approx H/4,L/4
            GETC; if (ii==-1)
              ERR1("Error: Missing Approx",nn);
            sos.ah=cc>>4; sos.al=cc&0xF;
            MSG3("  Approx H,L: %u,%u",nn-1,
              (N2)sos.ah,(N2)sos.al);
            if (sos.ah || sos.al)
              ERR1("Error: Invalid Approx",nn-1);
            ll-=3;
            break;
          case 0xDB:
            MSG1("Marker: DQT",nn-4); do {
            if (qn>=QMAX)
              ERR1("Error: More DQT",nn-4);
            // Precision,QID (1)
            if (ll<1)
              ERR1("Error: Missing Prec/Qid: Len",nn);
            GETC; if (ii==-1)
              ERR1("Error: Missing Prec/Qid: Eof",nn);
            qtab[qn].prec=cc>>4; qtab[qn].qid=cc&0xF;
            MSG3("  Prec: %u (%u)",nn-1,
              8u<<qtab[qn].prec,(N2)qtab[qn].prec);
            MSG2("  Qid: %u",nn-1,(N2)qtab[qn].qid);
            if (qtab[qn].prec!=0)
              ERR1("Error: Invalid Prec",nn-1);
            if (qtab[qn].qid>=QMAX)
              ERR1("Error: Invalid Qid",nn-1);
            ll-=1;
            // Qtab (64)
            if (ll<(64<<qtab[qn].prec))
              ERR2("Error: Missing Qtab (%u)",nn,(N2)qn);
            for (c1=0;c1<64;++c1)
            { if ((c1&0x7)==0)
                INF1("[%08lX] ",nn);
              GETC; if (ii==-1)
                ERR1("Error: Missing Quant",nn);
              if (!cc)
                ERR2("Error: Zero Quant(%u)",nn-1,(N2)c1);
              qtab[qn].tab[c1]=(N2)cc;
              INF1("  %2u",(N2)cc);
              if ((c1&0x7)==7)
                INF0("\n");
            } ll-=64<<qtab[qn].prec;
            ++qn; } while (ll);
            break;
          case 0xC4:
            MSG1("Marker: DHT",nn-4); do {
            if (hn>=HMAX)
              ERR1("Error: More DHT",nn-4);
            if (ll<17)
              ERR2("Error: Missing Htab (%u)",nn,(N2)hn);
            // Type,Hid (1)
            GETC; if (ii==-1)
              ERR1("Error: Missing Typ/Hid",nn);
            htab[hn].typ=cc>>4; htab[hn].hid=cc&0xF;
            if (htab[hn].typ>1)
              ERR2("Error: Invalid Typ: %u",nn-1,
              (N2)htab[hn].typ);
            if (htab[hn].hid>=HNUM)
              ERR2("Error: Invalid Hid: %u",nn-1,
              (N2)htab[hn].hid);
            MSG3("  Typ: %s (%u)",nn-1,
              htyp[htab[hn].typ],(N2)htab[hn].typ);
            MSG2("  Hid: %u",nn-1,(N2)htab[hn].hid);
            MSG1("  Bits/Vals:",nn-1);
            // Length (16)
            INF1("[%08lX] ",nn);
            for (n2=0,c1=0;c1<16;++c1)
            { GETC; if (ii==-1)
                ERR2("Error: Missing Len(%u)",nn,(N2)c1);
              htab[hn].len[c1]=cc; n2+=(N4)cc;
              INF1("  %u",(N2)cc);
            } ll-=17;
            INF0("\n");
            htab[hn].hufnum=n2;
            // Values (n2)
            jpg->htab[hn].val=htab[hn].val=MemGet(n2);
            if (!htab[hn].val)
              ERR2("Error: Nomem: Val[%lu]",nn,n2);
            if (ll<n2)
              ERR2("Error: Missing Val[%lu]",nn,n2);
            MSG2("  (ValLen): %lu",nn,n2);
            for (n1=0;n1<n2;++n1)
            { if ((n1&0xF)==0)
                INF1("[%08lX] ",nn);
              GETC; if (ii==-1)
                ERR2("Error: Missing Val(%lu)",nn,n1);
              htab[hn].val[n1]=cc;
              INF1("  %u",(N2)cc);
              if ((n1&0xF)==0xF)
                INF0("\n");
            } ll-=n2;
            if (n1&0xF) INF0("\n");
            // hufsiz,hufcod
            jpg->htab[hn].hufsiz=htab[hn].hufsiz=MemGet(htab[hn].hufnum*1);
            jpg->htab[hn].hufcod=htab[hn].hufcod=MemGet(htab[hn].hufnum*2);
            if (!htab[hn].hufsiz)
              ERR2("Error: Nomem: HufSiz[%u]",nn,htab[hn].hufnum);
            if (!htab[hn].hufcod)
              ERR2("Error: Nomem: HufCod[%u]",nn,htab[hn].hufnum);
            if (PrepTab(htab+hn,nn)==-1l) return (-1l);
            MSG2("  (Codes): %lu",nn,htab[hn].hufnum);
            // hufsiz,hufcod
            for (n1=0;n1<htab[hn].hufnum;++n1)
            { if ((n1&0x7)==0)
                INF1("[%08lX] ",nn);
              INF2("  %u:%04X",
                (N2)htab[hn].hufsiz[n1],
                htab[hn].hufcod[n1]);
              if ((n1&0x7)==0x7)
                INF0("\n");
            }
            if (n1&0x7) INF0("\n");
            ++hn; } while (ll);
            break;
          case 0xFE:
            WARN1("Warn: Marker: COM",nn-4);
            break;
          case 0xDD:
            MSG1("Marker: DRI",nn-4);
            if (ll!=2)
              ERR1("Error: Invalid Length",nn);
            // Restart Interval (2)
            GETC; if (ii==-1)
              ERR1("Error: Missing Restart Interval/1",nn);
            sos.dri=(N2)cc;
            GETC; if (ii==-1)
              ERR1("Error: Missing Restart Interval/2",nn-1);
            sos.dri=(sos.dri<<8)|(N2)cc;
            MSG2("  RestIval : %u",nn-2,sos.dri);
            ll-=2;
            break;
          default:
            WARN1("Warn: Unknown Marker",nn-4);
            break;
        }
    }
  }
  if (ll) ERR1("Error: Unexpected EOF",nn);

  return (0);
}

I4 conv2(N4 *nn,tJpeg2 *jpg,tSof *sof,tComp *comp,tComp2 *comp2,
  tHtab *htab,tQtab *qtab,tGetBit *bb,FILE *f1)
{ tBmp bmp; N1 c1; N4 n1,n2;
  N1 *pp[CNUM],dd2[64];
  I2 dd[64],dd0[CNUM];
  RI rr1[64],rr2[64];
  N2 xd,yd,xm,ym;
  N2 i1,i2,i3,i4;

  // Initalizing
  xd=yd=0;
  for (n1=0;n1<CNUM;++n1) dd0[n1]=0;
  for (n1=0;n1<CNUM;++n1)
  { if (comp[n1].xd>xd) xd=comp[n1].xd;
    if (comp[n1].yd>yd) yd=comp[n1].yd;
  }
  i1=comp[0].xd*comp[0].yd;
  i2=comp[1].xd*comp[1].yd+i1;
  i3=comp[2].xd*comp[2].yd+i2;
  xd*=8; xm=(sof->xl+xd-1)/xd*xd; xd/=8;
  yd*=8; ym=(sof->yl+yd-1)/yd*yd; yd/=8;
  for (n2=0,n1=0;n1<CNUM;++n1)
    n2+=(comp[n1].xd*(N4)xm/xd/8)*
        (comp[n1].yd*(N4)ym/yd/8);
  MSG4("Image (%u,%u) (%lu)",*nn-1,xm,ym,n2);
  for (i4=xd*yd*64,n1=0;n1<CNUM;++n1)
    if (!(jpg->pp[n1]=pp[n1]=MemGet(i4)))
      ERR3("Error: Image: Nomem: PP%u[%u]",*nn-1,n1+1,i4);
  for (i4=0;i4<50;i4+=i3); if (i4>50) i4-=i3;
  bmp.pp=NULL; jpg->bmp=&bmp;
  if (BmpWrite1(&bmp,f1,xm,ym,sof->xl,sof->yl)==-1l)
    ERR1("Error: Image: BmpWrite1",*nn-1);

  // DataUnit (8x8)
  for (n1=0;n1<n2;++n1)
  { I4 ii; N1 cid=n1%i3;
    tHtab *h1; tQtab *q1;
    cid=(cid<i1)?0:(cid<i2)?1:2;
    if (n1%i4==0)
      DEB2("[%08lX+%u] ",
      *nn-1,8-bb->cnt);
    if (n1%i3==0)
      DEB0("<");
    // !! Decode !!
    h1=getht(htab,comp2[cid].hdc,0);
    if (!h1) ERR3("Error: Image: Htab %u(%u,0)",
      *nn-1,(N2)cid,(N2)comp2[cid].hdc);
    dd[0]=dd0[cid];
    ii=GetDC(bb,h1,dd+0);
    dd0[cid]=dd[0];
    if (ii==-1l) return (-1l);
    h1=getht(htab,comp2[cid].hac,1);
    if (!h1) ERR3("Error: Image: Htab %u(%u,1)",
      *nn-1,(N2)cid,(N2)comp2[cid].hac);
    ii=GetAC(bb,h1,dd+1);
    if (ii==-1l) return (-1l);
    DEB0(".");
    if (n1==0) dumpI2("Decode",dd);
    // !! Quant2,ZigZag2 !!
    q1=getqt(qtab,comp[cid].qid);
    if (!q1) ERR3("Error: Image: Qtab %u(%u)",
      *nn-1,(N2)cid,(N2)comp[cid].qid);
    if (Quant2(q1->tab,dd,rr1)==-1l) return (-1l);
    if (n1==0) dumpRI("Quant2",rr1);
    if (ZigZag(zz2,rr1,rr2)==-1l) return (-1l);
    if (n1==0) dumpRI("ZigZag2",rr2);
    // !! DCT2,LevelShift2 !!
    if (DCT2(tt,rr2,rr1)==-1l) return (-1l);
    if (n1==0) dumpRI("DCT2",rr1);
    if (LevelShift2(rr1,dd2)==-1l) return (-1l);
    if (n1==0) dumpN1("LevelShift2",dd2);
    // !! DU store !!
    { I2 x1,y1; c1=n1%i3;
      c1-=(c1<i1)?0:(c1<i2)?i1:i2;
      y1=c1/comp[cid].xd;
      x1=c1%comp[cid].xd;
      ddcp(dd2,ddyx(pp[cid],xd,y1,x1));
      // !! MCU fill !!
      if (n1%i3==i3-1)
      { for (c1=0;c1<CNUM;++c1)
        { Str s1,s2; N2 x2,y2;
          N2 xl=comp[c1].xd;
          N2 yl=comp[c1].yd;
          N2 x1a,x1b,x2a,x2b,kk;
          N2 y1a,y1b,y2a,y2b,xd2=xd*64;
          y2=yl*8; y1a=0; y1b=0;
          s1=pp[c1]; s2=pp[c1];
          if (xl!=xd)
            for (y1=0;y1<y2;++y1)
          { x1=xd*8-1; x1a=x1/8; x1b=x1%8;
            x2=x1*xl/xd; x2a=x2/8; x2b=x2%8;
            s1+=x1a*64+x1b; s2+=x2a*64+x2b;
            for (kk=x1*xl%xd;x1>=0;--x1)
            { //s1=ddyx(pp[c1],xd,y1/8,x1/8);
              //s2=ddyx(pp[c1],xd,y1/8,x2/8);
              //s1[y1%8*8+x1%8]=s2[y1%8*8+x2%8];
              *s1=*s2; --s1;
              if (--x1b==0xFFFF)
              { --x1a; x1b=7; s1-=56; }
              if ((kk-=xl)>=0x8000)
              { kk+=xd; --x2; --s2;
                if (--x2b==0xFFFF)
                { --x2a; x2b=7; s2-=56; }
              }
            } s1+=57; s2+=57;
            if (++y1b==8)
            { ++y1a; y1b=0;
              s1+=xd2-7*8;
              s2+=xd2-7*8;
            } else
            { s1+=8; s2+=8; }
          }
          y1=yd*8-1; y1a=y1/8; y1b=y1%8;
          y2=y1*yl/yd; y2a=y2/8; y2b=y2%8;
          s1=pp[c1]+y1a*xd2+y1b*8;
          s2=pp[c1]+y2a*xd2+y2b*8;
          if (yl!=yd)
            for (kk=y1*yl%yd;y1>=0;--y1)
          { Str t1=s1,t2=s2;
            x2=xd*8; x1a=0; x1b=0;
            for (x1=0;x1<x2;++x1)
            { //s1=ddyx(pp[c1],xd,y1/8,x1/8);
              //s2=ddyx(pp[c1],xd,y2/8,x1/8);
              //s1[y1%8*8+x1%8]=s2[y2%8*8+x1%8];
              *s1=*s2; ++s1; ++s2;
              if (++x1b==8)
              { ++x1a; x1b=0; s1+=56; s2+=56; }
            } s1=t1; s2=t2;
            if (--y1b!=0xFFFF) s1-=8; else
            { --y1a; y1b=7; s1-=xd2-7*8; }
            if ((kk-=yl)>=0x8000)
            { kk+=yd; --y2;
              if (--y2b!=0xFFFF) s2-=8; else
              { --y2a; y2b=7; s2-=xd2-7*8; }
            }
          }
        }
      }
    }
    // !! Display !!
    if (n1%i3==i3-1)
    { Str s1,s2,s3;
      N2 x1,y1,x2,y2;
      N4 n3=n1/i3;
      N2 y=(N2)(n3/(xm/xd/8));
      N2 x=(N2)(n3%(xm/xd/8));
      N2 i1x,i1y,i2x,i2y;
      x*=xd*8; y*=yd*8;
      s1=pp[0]; s2=pp[1]; s3=pp[2];
      for (i1y=y,y1=0;y1<yd;++y1,i1y+=8)
      { for (i1x=x,x1=0;x1<xd;++x1,i1x+=8)
        { //s1=ddyx(pp[0],xd,y1,x1);
          //s2=ddyx(pp[1],xd,y1,x1);
          //s3=ddyx(pp[2],xd,y1,x1);
          for (i2y=i1y,y2=0;y2<8;++y2,++i2y)
          { for (i2x=i1x,x2=0;x2<8;++x2,++i2x)
            { Color2(s1,s2,s3);
              BmpSet(&bmp,i2x,i2y,
                *(s1++),*(s2++),*(s3++));
            }
          }
        }
      }
    }
    if (n1%i3==i3-1)
      DEB0(">");
    if (n1%i4==i4-1)
      DEB0("\n");
  }
  if (n1%i4) DEB0("\n");

  // Finishing
  while (bb->cnt)
  { I4 ii=GetBit(bb);
    if (ii==-1l) break;
    if (ii) continue;
    WARN1("Warn: Image: HufEnd",*nn-1);
  }
  if (BmpWrite2(&bmp)==-1l)
    ERR1("Error: Image: BmpWrite2",*nn);
  return (0);
}


#endif
